package com.yami.shop.service.impl;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yami.shop.bean.model.Supplier;
import com.yami.shop.bean.model.SupplierCategory;
import com.yami.shop.bean.vo.SupplierVO;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.i18n.I18nMessage;
import com.yami.shop.common.i18n.LanguageEnum;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.common.util.PoiExcelUtil;
import com.yami.shop.common.util.PrincipalUtil;
import com.yami.shop.dao.SupplierMapper;
import com.yami.shop.service.SupplierCategoryService;
import com.yami.shop.service.SupplierService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author SJL
 * @date 2020-08-25 15:50:06
 */
@Slf4j
@Service
public class SupplierServiceImpl extends ServiceImpl<SupplierMapper, Supplier> implements SupplierService {

    @Autowired
    private SupplierMapper supplierMapper;
    @Autowired
    private SupplierCategoryService supplierCategoryService;
    private final int MAX_LENGTH = 50;

    @Override
    public IPage<Supplier> pageShop(PageParam<Supplier> page, Supplier supplier) {
        return supplierMapper.pageShop(page, supplier);
    }

    @Override
    public IPage<SupplierVO> pageProdSupplier(PageParam<Supplier> page, Supplier supplier) {
        return supplierMapper.pageProdSupplier(page, supplier);
    }

    @Override
    public void exportSupplier(Supplier supplier, HttpServletResponse response) {
        List<Supplier> supplierList = supplierMapper.getByParam(supplier);
        createExcel(supplierList, supplier.getShopId(), response, false);
    }

    @Override
    public void downLoadModel(Long shopId, HttpServletResponse response) {
        createExcel(null, shopId, response, true);
    }

    @Override
    public Object parseFile(MultipartFile file, Long shopId) throws Exception {
        Integer lang = I18nMessage.getDbLang();
        try (InputStream inputStream = file.getInputStream();
             Workbook workbook = WorkbookFactory.create(inputStream)) {
            Sheet sheet = workbook.getSheetAt(0);
            int rowNumber = sheet.getPhysicalNumberOfRows();
            if (rowNumber <= Constant.EXCEL_BEGIN_ROW) {
                // 文件无内容
                throw new YamiShopBindException("yami.document.no.content");
            }
            if (!(file.getOriginalFilename().contains(Constant.XLS_FILE) || file.getOriginalFilename().contains(Constant.XLSX_FILE))) {
                // 格式错误
                throw new YamiShopBindException("yami.file.error");
            }
            List<String> supplierNameList = supplierMapper.listSupplierName(shopId);
            List<SupplierCategory> categoryList = supplierCategoryService.list(new LambdaQueryWrapper<SupplierCategory>()
                    .eq(SupplierCategory::getStatus, 1)
                    .eq(SupplierCategory::getShopId, shopId));
            Map<String, Long> categoryMap = new HashMap<>(categoryList.size());
            if (CollectionUtil.isNotEmpty(categoryList)) {
                categoryMap = categoryList.stream().collect(Collectors.toMap(SupplierCategory::getName, SupplierCategory::getSupplierCategoryId));
            }
            List<Supplier> suppliers = new ArrayList<>();
            List<String> errorList = new ArrayList<>();
            HashSet<String> nameSet = new HashSet<>();
            String response;
            int insertRows = 0;
            for (int i = 2; i < rowNumber; i++) {
                try {
                    Row row = sheet.getRow(i);
                    int cell = 0;
                    //{"供应商名称", "供应商分类", "单位电话", "联系人", "联系电话", "QQ", "微信号", "邮箱", "传真"}
                    String supplierName = PoiExcelUtil.getRowValue(row, cell, false);
                    String supplierCategoryName = PoiExcelUtil.getRowValue(row, ++cell, false);
                    String tel = PoiExcelUtil.getRowValue(row, ++cell, false);
                    String contactName = PoiExcelUtil.getRowValue(row, ++cell, false);
                    String contactTel = PoiExcelUtil.getRowValue(row, ++cell, false);
                    String qqNumber = PoiExcelUtil.getRowValue(row, ++cell, false);
                    String wxNumber = PoiExcelUtil.getRowValue(row, ++cell, false);
                    String mail = PoiExcelUtil.getRowValue(row, ++cell, false);
                    String fax = PoiExcelUtil.getRowValue(row, ++cell, false);
                    checkData(supplierNameList, categoryMap, nameSet, supplierName, supplierCategoryName, tel, contactName, contactTel, mail, qqNumber, wxNumber);
                    nameSet.add(supplierName);
                    Supplier supplier = getSupplier(shopId, categoryMap, supplierName, supplierCategoryName, tel, contactName, contactTel, qqNumber, wxNumber, mail, fax);
                    insertRows++;
                    suppliers.add(supplier);
                } catch (Exception e) {
                    errorList.add("第" + (i + 1) + "行数据有错误：" + e.getMessage());
                }
            }
            //供应商不为空批量导入
            if (CollectionUtil.isNotEmpty(suppliers)) {
                int errorCount = 0;
                saveBatch(suppliers);
                response = "检查到" + insertRows + "条供应商信息，成功导入" +
                        (suppliers.size() - errorCount) + "条供应商信息！错误" + errorCount + "条供应商信息！" +
                        (CollUtil.isNotEmpty(errorList) ? errorList.toString() : "");
                return response;
            }
            response = Objects.equals(lang, LanguageEnum.LANGUAGE_ZH_CN.getLang()) ? "数据错误!导入0条" : "Data error! Import 0 items";
            if (CollUtil.isNotEmpty(errorList)) {
                response = response + errorList.toString();
            }
            return response;
        } catch (Exception e) {
            return e.getMessage();
        }
    }

    private void checkData(List<String> supplierNameList, Map<String, Long> categoryMap, HashSet<String> nameSet, String supplierName, String supplierCategoryName, String tel, String contactName, String contactTel, String mail, String qqNumber, String wxNumber ) {
        if (StrUtil.isBlank(supplierName)) {
            //供应商名称不能为空
            throw new YamiShopBindException("yami.supplier.name.not.blank");
        }
        if (StrUtil.isNotBlank(supplierName) && supplierName.length() > MAX_LENGTH) {
            //供应商名称字数不能超过50
            throw new YamiShopBindException("yami.supplier.supplierName.than");
        }
        boolean isExist = CollectionUtil.isNotEmpty(supplierNameList) && (supplierNameList.contains(supplierName) || nameSet.contains(supplierName));
        if (isExist) {
            //供应商名称已存在
            throw new YamiShopBindException("yami.supplier.supplierName.exist");
        }
        if (Objects.isNull(categoryMap.get(supplierCategoryName)) && !StrUtil.isBlank(supplierCategoryName)) {
            //供应商分类不存在或已被禁用
            throw new YamiShopBindException("yami.supplier.category.not.exit");
        }
        if (Objects.nonNull(contactName) && contactName.length() > MAX_LENGTH) {
            //联系人名称不能超过50
            throw new YamiShopBindException("yami.supplier.contactName.than");
        }
        if (Objects.nonNull(tel) && !PrincipalUtil.isTel(tel)) {
            //单位电话格式错误
            throw new YamiShopBindException("yami.supplier.tel.error");
        }
        if (Objects.nonNull(contactTel) && !PrincipalUtil.isMobile(contactTel)) {
            //联系电话格式错误
            throw new YamiShopBindException("yami.supplier.contactTel.error");
        }
        if (Objects.nonNull(mail) && !PrincipalUtil.isMail(mail)) {
            //邮箱格式错误
            throw new YamiShopBindException("yami.supplier.mail.error");
        }
        if (Objects.nonNull(qqNumber) && !PrincipalUtil.isQQNumber(qqNumber)) {
            //qq号格式错误
            throw new YamiShopBindException("yami.supplier.qqNumber.error");
        }
        if (Objects.nonNull(wxNumber) && !PrincipalUtil.isWxNumber(wxNumber)) {
            //微信号格式错误
            throw new YamiShopBindException("yami.supplier.wxNumber.error");
        }
    }

    @NotNull
    private Supplier getSupplier(Long shopId, Map<String, Long> categoryMap, String supplierName, String supplierCategoryName, String tel, String contactName, String contactTel, String qqNumber, String wxNumber, String mail, String fax) {
        Supplier supplier = new Supplier();
        supplier.setShopId(shopId);
        supplier.setContactTel(contactTel);
        supplier.setSupplierName(supplierName);
        supplier.setSupplierCategoryId(categoryMap.get(supplierCategoryName));
        supplier.setTel(tel);
        supplier.setContactName(contactName);
        supplier.setQqNumber(qqNumber);
        supplier.setWxNumber(wxNumber);
        supplier.setMail(mail);
        supplier.setFax(fax);
        supplier.setIsDefault(0);
        return supplier;
    }

    @Override
    public Integer getCountByName(String supplierName, Long supplierId,Long shopId) {
        return supplierMapper.getCountByName(supplierName, supplierId,shopId);
    }

    @Override
    public List<Supplier> getByShopId(Long shopId) {
        return supplierMapper.getByShopId(shopId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateSupplier(Supplier supplier) {
        if (Objects.isNull(supplier.getSupplierCategoryId())) {
            supplierMapper.updateSupplierCategory(supplier.getSupplierId());
        }
        supplierMapper.updateById(supplier);
        return true;
    }

    @Override
    public void updateSupplierByCategoryId(Long supplierCategoryId) {
        supplierMapper.updateSupplierByCategoryId(supplierCategoryId);
    }

    private void createExcel(List<Supplier> suppliers, Long shopId, HttpServletResponse response, boolean isModel) {
        ExcelWriter writer = ExcelUtil.getBigWriter();
        List<String> headerList;
        String[] headerCn;
        String[] headerEn;
        if (BooleanUtil.isFalse(isModel)) {
            headerCn = new String[]{"供应商名称(*必填)", "供应商分类", "单位电话", "联系人", "联系电话", "QQ", "微信号", "邮箱", "传真", "地址"};
            headerEn = new String[]{"Supplier Name(*Require)", "Supplier Category", "Tel", "Contact Name", "Contact Tel", "QQ", "WX Number", "Mail", "Fax", "Address"};
        } else {
            headerCn = new String[]{"供应商名称", "供应商分类", "单位电话", "联系人", "联系电话", "QQ", "微信号", "邮箱", "传真"};
            headerEn = new String[]{"Supplier Name", "Supplier Category", "Tel", "Contact Name", "Contact Tel", "QQ", "WX Number", "Mail", "Fax"};
        }
        headerList = Arrays.asList(Objects.equals(I18nMessage.getDbLang(), 0) ? headerCn : headerEn);
        Sheet sheet = writer.getSheet();
        sheet.setColumnWidth(0, 40 * 256);
        int length = headerCn.length;
        for (int i = 1; i < length; i++) {
            sheet.setColumnWidth(i, 20 * 256);
        }
        sheet.setColumnWidth(9, 50 * 256);
        writer.merge(headerList.size() - 1, Objects.equals(I18nMessage.getDbLang(), 0) ? "供应商信息" : "Supplier information");
        writer.writeRow(headerList);
        try (Workbook workbook = writer.getWorkbook()) {
            List<SupplierCategory> categoryList;
            //供应商分类
            if (BooleanUtil.isFalse(isModel)) {
                categoryList = supplierCategoryService.listSupplierCategory(shopId, 0);
            } else {
                categoryList = supplierCategoryService.listSupplierCategory(shopId, 1);
            }
            if (CollectionUtil.isNotEmpty(categoryList)) {
                String[] categoryName = new String[categoryList.size()];
                for (int i = 0; i < categoryList.size(); i++) {
                    categoryName[i] = categoryList.get(i).getName();
                }
                PoiExcelUtil.createDropDownList(workbook, sheet, Arrays.asList(categoryName), 1, 5000, 1, 1);
            }
            int row = 1;
            if (CollectionUtil.isNotEmpty(suppliers)) {
                for (Supplier supplier : suppliers) {
                    int firstRow = ++row;
                    int col = -1;
                    //供应商名称
                    PoiExcelUtil.mergeIfNeed(writer, firstRow, firstRow, ++col, col, supplier.getSupplierName());
                    //供应商分类
                    PoiExcelUtil.mergeIfNeed(writer, firstRow, firstRow, ++col, col, supplier.getCategoryName());
                    //单位电话
                    PoiExcelUtil.mergeIfNeed(writer, firstRow, firstRow, ++col, col, supplier.getTel());
                    //联系人
                    PoiExcelUtil.mergeIfNeed(writer, firstRow, firstRow, ++col, col, supplier.getContactName());
                    //联系电话
                    PoiExcelUtil.mergeIfNeed(writer, firstRow, firstRow, ++col, col, supplier.getContactTel());
                    //QQ
                    PoiExcelUtil.mergeIfNeed(writer, firstRow, firstRow, ++col, col, supplier.getQqNumber());
                    //微信号
                    PoiExcelUtil.mergeIfNeed(writer, firstRow, firstRow, ++col, col, supplier.getWxNumber());
                    //邮箱
                    PoiExcelUtil.mergeIfNeed(writer, firstRow, firstRow, ++col, col, supplier.getMail());
                    //传真
                    PoiExcelUtil.mergeIfNeed(writer, firstRow, firstRow, ++col, col, supplier.getFax());
                    //地址
                    PoiExcelUtil.mergeIfNeed(writer, firstRow, firstRow, ++col, col, supplier.getAddr());
                }
            }
            PoiExcelUtil.writeExcel(response, writer);
        } catch (Exception e) {
            log.error("创建Excel错误:", e);
        }
    }
}
